 
import { REACTION_SOURCE } from "utils/constants/constants";
import { priority } from "utils/constants/definetypes";
import { generateUniqueId } from "utils/utils";

 

export class LabTaskHelper
{
    private static minerialCompose:Record<MineralCompoundConstant,Record<ResourceConstant,number>>= {} as any;
    // static createLabTask<T extends ILabArg >(id:string,arg:T,region:string,code:tasktype,priority:number=priority.A,expire=300):ILabTask<T>
    // {
    //     const task:ILabTask<T>={
    //         ID:id ,
    //         region:region,
    //         code:code,
    //         priority:priority,
    //         arg:arg,
    //         expire:Game.time+expire
    //     };
    //     return task;
    // }
    static createReaction(arg:IRectionTask)
    {
        const task :ITaskDeclare["react"]={
            id:generateUniqueId(),
            priority:priority.S,
            ttl:5000,
            type:"react",
            data:{
                type:"react",
                arg:arg,
            },
            shard:0,
        };
        return task
    }
    static createReactionTask(roomName:string,target:MineralBoostConstant,amount:number)
    {
        const task :ITaskDeclare["react"]={
            id:generateUniqueId(),
            priority:priority.S,
            ttl:5000,
            type:"react",
            data:{
                type:"react",
                arg:{
                     RectionTarget:target,
                     TargetCount:amount,
                     Reactions:[],
                     State:-1,

                },
            },
            shard:0,
        };
        return task
    }
    static getReactionArg(Target:(MineralCompoundConstant),TargetCount:number):IRectionTask
    {
        const reactiontask:IRectionTask = { RectionTarget:Target,TargetCount:TargetCount,Reactions:[],State:-1};
        return reactiontask;
    }

    static getBoostArg( resz:BoostResourceConfig[]):IBoostTask
    {
        const reactiontask:IBoostTask = { res:resz ,State:-1};
        return reactiontask;
    }

    static GetReactant(param:IRectionTask):LabReaction|undefined
    {
        if(param.Reactions.length>0)
        {
            return param.Reactions[param.Reactions.length-1];
        }
        return undefined;
    }

    static pushParam(param:Record<string ,ITransportItem[]>,item:ITransportItem,resourceType:ResourceConstant)
    {
        if(param[resourceType])
        {
            param[resourceType].push(item);
        }
        else
        {
            param[resourceType]=[item];
        }

    }

    /**
     * 计算化合物的反应栈
     * @param lbtarget 最终产物
     * @param store 底物仓库，如果不传入则只计算最终产物的底物，如果传入则递归判断直到可以找到完整的生产栈
     * @returns
     */
    static  CreateReationStack(lbtarget:LabTarget ,store?:StoreDefinition):LabReaction[]
    {
        // 左右根
        const Baseminerial = REACTION_SOURCE[lbtarget.target];
        const reactstack: LabReaction[] = [];
        if (Baseminerial && Baseminerial.length == 2)
        {
            lbtarget.amount=0;
            const baseA:LabTarget={target: Baseminerial[0], number: lbtarget.number };
            const baseB:LabTarget={target: Baseminerial[1], number: lbtarget.number };
            reactstack.push({Reactant:lbtarget,BaseA:baseA,BaseB:baseB});

            if(store && store[baseA.target]<baseA.number)
            {
                const leftReact = this.CreateReationStack({ target: Baseminerial[0], number: lbtarget.number },store);
                reactstack.push(...leftReact);
            }

            if(store && store[baseB.target]<baseB.number)
            {
                const rightReact = this.CreateReationStack({ target: Baseminerial[1], number: lbtarget.number },store);
                reactstack.push(...rightReact);
            }

            return reactstack;
        }
        else {
            return [];
        }
    }
    static getReactionBaseMinerial(lbtarget:LabTarget):Record<ResourceConstant,number>
    {
        const base =    REACTION_SOURCE[lbtarget.target];
        const map:any={};
        for(const b of base)
        {
            if(map[b])
            {
                map[b]=map[b]+1;
            }
            else
            {
                map[b]=1;
            }
        }
        return map;
    }
    public static getMinerialComposeRecord(resourceType:MineralCompoundConstant)
    {
        if(this.minerialCompose[resourceType])
        {
            return this.minerialCompose[resourceType];
        }
        this.minerialCompose[resourceType] = this.getMinerialCompose(resourceType);
        return this.minerialCompose[resourceType];
    }
    private static getMinerialCompose(resourceType:MineralCompoundConstant):Record<ResourceConstant,number>
    {
        const base =    REACTION_SOURCE[resourceType];
        const map:Record<string,number>={};
        for(const b of base)
        {
            if(REACTION_SOURCE[b])
            {
                // 化合物
                const childmap = this.getMinerialCompose(b as MineralCompoundConstant);
                for(const key in childmap)
                {
                    if(map[key])
                    {
                        map[key]=map[key]+childmap[key as  ResourceConstant];
                    }
                    else
                    {
                        map[key]=childmap[ key as  ResourceConstant];
                    }
                }
            }
            else
            {
                // 基础元素
                if(map[b])
                {
                    map[b]=map[b]+1;
                }
                else
                {
                    map[b]=1;
                }
            }
        }
        return map;
    }
    // 判断仓库的资源是否满足反应的所有底物条件,递归太消耗cpu了。
    static  IsReationBaseEnough(lbtarget:LabTarget,store:StoreDefinition,deep:number=0):boolean
    {
        if(store[lbtarget.target] && store[lbtarget.target]>=lbtarget.number)
        {
            store[lbtarget.target] -=lbtarget.number;
            // store 数量足够
            return true;
        }
        // 否则判断底物是否足够
        // 左右根
        if(deep>=1)
        {
            return false;
        }
        const Baseminerial = REACTION_SOURCE[lbtarget.target];
        const reactstack: LabReaction[] = [];
        if (Baseminerial && Baseminerial.length == 2)
        {
            const baseA:LabTarget={target: Baseminerial[0], number: lbtarget.number};
            const baseB:LabTarget={target: Baseminerial[1], number: lbtarget.number};
            return this.IsReationBaseEnough(baseA,store,deep+1) && this.IsReationBaseEnough(baseB,store,deep+1);
        }
         return false;
    }


    static  IsReationBaseEnoughs(lbtarget:LabTarget,stores:StoreDefinition[],res:{type:ResourceConstant,num:number},deep:number=0):boolean|-1
    {
        // 1.任意一个满足条件则满足条件
        for(const store of stores)
        {
            //
            if(store[lbtarget.target] && store[lbtarget.target]>=lbtarget.number)
            {
                store[lbtarget.target] -=lbtarget.number;
                // store 数量足够
                return true;
            }
        }
        if(deep>=1)
        {
            return false;
        }
        // 2.如果store之和满足条件
        let sum = _.sum(stores,(store)=>store[lbtarget.target]);
        if(sum>=lbtarget.number)
        {
            // 需要的数量 减去 storage的数量
            const transportcount = res.num-stores[0][lbtarget.target];
            res.num =transportcount;
            res.type= lbtarget.target;
            return -1;
        }

        // 3.否则判断底物是否足够,1和2都不满足只能去找底物是否满足条件
        // 左右根
        const Baseminerial = REACTION_SOURCE[lbtarget.target];

        if (Baseminerial && Baseminerial.length == 2)
        {
            const baseA:LabTarget={target: Baseminerial[0], number: lbtarget.number};
            const baseB:LabTarget={target: Baseminerial[1], number: lbtarget.number};
            const res1 = this.IsReationBaseEnoughs(baseA,stores,res,deep);
            const res2 =this.IsReationBaseEnoughs(baseB,stores,res,deep);
            if(res1=== true && res2=== true)
            {
                return true;
            }
            if(res1=== -1 || res2=== -1)
            {
                // 只要有一个是-1 就需要运输
                return -1;
            }
            return false;
        }
         return false;
    }

    /**
     * 判断这个反应的底物是否足够
     * @param Reactiontarget 反应要生成的最终产物
    */
    static  IsReationResourceEnoughs(Reactiontarget:LabTarget,stores:StoreDefinition[],res:{type:ResourceConstant,num:number},deep:number=0):boolean|-1
    {
        const Baseminerial = REACTION_SOURCE[Reactiontarget.target];
        if (Baseminerial && Baseminerial.length == 2)
        {
            const baseA:LabTarget={target: Baseminerial[0], number: Reactiontarget.number};
            const baseB:LabTarget={target: Baseminerial[1], number: Reactiontarget.number};
            const res1 = this.IsReationBaseEnoughs(baseA,stores,res,deep);
            const res2 =this.IsReationBaseEnoughs(baseB,stores,res,deep);
            if(res1=== true && res2=== true)
            {
                return true;
            }
            if(res1=== -1 || res2=== -1)
            {
                // 只要有一个是-1 就需要运输
                return -1;
            }
            return false;
        }
         return false;
    }
 /**
     * 判断这个反应的底物是否足够
     * @param Reactiontarget 反应要生成的最终产物
    */
  static  IsReationResourceEnough(Reactiontarget:LabTarget,store:StoreDefinition,deep:number=0):boolean|-1
  {
      const Baseminerial = REACTION_SOURCE[Reactiontarget.target];
      if (Baseminerial && Baseminerial.length == 2)
      {
          const baseA:LabTarget={target: Baseminerial[0], number: Reactiontarget.number};
          const baseB:LabTarget={target: Baseminerial[1], number: Reactiontarget.number};
          return this.IsReationBaseEnough(baseA,store,deep+1) && this.IsReationBaseEnough(baseB,store,deep+1);
      }
       return false;
  }


}
